﻿using System;
using MugenInjection.Logging.Components;
using MugenInjection.Logging.Infrastructure;
using MugenInjection.Logging.Interface;
using NLog;
using LogLevel = NLog.LogLevel;

namespace MugenInjection.Logging.NLog2.Infrastructure
{
    /// <summary>
    /// A logger that integrates with NLog2.
    /// </summary>
    public class NLogLogger : LoggerBase
    {
        #region Fields

        private readonly Logger _logger;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="NLogLogger"/> class.
        /// </summary>
        public NLogLogger(LoggerFactoryComponent loggerFactory, Type type)
            : base(loggerFactory, type)
        {
            _logger = LogManager.GetLogger(type.FullName);
        }

        #endregion

        #region Overrides of LoggerBase

        /// <summary>
        /// Gets a value indicating whether messages with Debug severity should be logged.
        /// </summary>
        public override bool IsDebugEnabled
        {
            get { return _logger.IsDebugEnabled; }
        }

        /// <summary>
        /// Gets a value indicating whether messages with Info severity should be logged.
        /// </summary>
        public override bool IsInfoEnabled
        {
            get { return _logger.IsInfoEnabled; }
        }

        /// <summary>
        /// Gets a value indicating whether messages with Trace severity should be logged.
        /// </summary>
        public override bool IsTraceEnabled
        {
            get { return _logger.IsTraceEnabled; }
        }

        /// <summary>
        /// Gets a value indicating whether messages with Warn severity should be logged.
        /// </summary>
        public override bool IsWarnEnabled
        {
            get { return _logger.IsWarnEnabled; }
        }

        /// <summary>
        /// Gets a value indicating whether messages with Error severity should be logged.
        /// </summary>
        public override bool IsErrorEnabled
        {
            get { return _logger.IsErrorEnabled; }
        }

        /// <summary>
        /// Gets a value indicating whether messages with Fatal severity should be logged.
        /// </summary>
        public override bool IsFatalEnabled
        {
            get { return _logger.IsFatalEnabled; }
        }

        /// <summary>
        /// Logs the specified message with Debug severity.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void Debug(string message)
        {
            LogInternal(LogLevel.Debug, message);
        }

        /// <summary>
        /// Logs the specified message with Debug severity.
        /// </summary>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Debug(string format, params object[] args)
        {
            LogInternal(LogLevel.Debug, format, args);
        }

        /// <summary>
        /// Logs the specified exception with Debug severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="message">The message.</param>
        public override void Debug(Exception exception, string message)
        {
            LogInternal(LogLevel.Debug, message, exception);
        }

        /// <summary>
        /// Logs the specified exception with Debug severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Debug(Exception exception, string format, params object[] args)
        {
            LogInternal(LogLevel.Debug, format, args, exception);
        }

        /// <summary>
        /// Logs the specified message with Info severity.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void Info(string message)
        {
            LogInternal(LogLevel.Info, message);
        }

        /// <summary>
        /// Logs the specified message with Info severity.
        /// </summary>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Info(string format, params object[] args)
        {
            LogInternal(LogLevel.Info, format, args);
        }

        /// <summary>
        /// Logs the specified exception with Info severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="message">The message.</param>
        public override void Info(Exception exception, string message)
        {
            LogInternal(LogLevel.Info, message, exception);
        }

        /// <summary>
        /// Logs the specified exception with Info severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Info(Exception exception, string format, params object[] args)
        {
            LogInternal(LogLevel.Info, format, args, exception);
        }

        /// <summary>
        /// Logs the specified message with Trace severity.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void Trace(string message)
        {
            LogInternal(LogLevel.Trace, message);
        }

        /// <summary>
        /// Logs the specified message with Trace severity.
        /// </summary>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Trace(string format, params object[] args)
        {
            LogInternal(LogLevel.Trace, format, args);
        }

        /// <summary>
        /// Logs the specified exception with Trace severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="message">The message.</param>
        public override void Trace(Exception exception, string message)
        {
            LogInternal(LogLevel.Trace, message, exception);
        }

        /// <summary>
        /// Logs the specified exception with Trace severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Trace(Exception exception, string format, params object[] args)
        {
            LogInternal(LogLevel.Trace, format, args, exception);
        }

        /// <summary>
        /// Logs the specified message with Warn severity.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void Warn(string message)
        {
            LogInternal(LogLevel.Warn, message);
        }

        /// <summary>
        /// Logs the specified message with Warn severity.
        /// </summary>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Warn(string format, params object[] args)
        {
            LogInternal(LogLevel.Warn, format, args);
        }

        /// <summary>
        /// Logs the specified exception with Warn severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="message">The message.</param>
        public override void Warn(Exception exception, string message)
        {
            LogInternal(LogLevel.Warn, message, exception);
        }

        /// <summary>
        /// Logs the specified exception with Warn severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Warn(Exception exception, string format, params object[] args)
        {
            LogInternal(LogLevel.Warn, format, args, exception);
        }

        /// <summary>
        /// Logs the specified message with Error severity.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void Error(string message)
        {
            LogInternal(LogLevel.Error, message);
        }

        /// <summary>
        /// Logs the specified message with Error severity.
        /// </summary>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Error(string format, params object[] args)
        {
            LogInternal(LogLevel.Error, format, args);
        }

        /// <summary>
        /// Logs the specified exception with Error severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="message">The message.</param>
        public override void Error(Exception exception, string message)
        {
            LogInternal(LogLevel.Error, message, exception);
        }

        /// <summary>
        /// Logs the specified exception with Error severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Error(Exception exception, string format, params object[] args)
        {
            LogInternal(LogLevel.Error, format, args, exception);
        }

        /// <summary>
        /// Logs the specified message with Fatal severity.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void Fatal(string message)
        {
            LogInternal(LogLevel.Fatal, message);
        }

        /// <summary>
        /// Logs the specified message with Fatal severity.
        /// </summary>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Fatal(string format, params object[] args)
        {
            LogInternal(LogLevel.Fatal, format, args);
        }

        /// <summary>
        /// Logs the specified exception with Fatal severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="message">The message or format template.</param>
        public override void Fatal(Exception exception, string message)
        {
            LogInternal(LogLevel.Fatal, message, exception);
        }

        /// <summary>
        /// Logs the specified exception with Fatal severity.
        /// </summary>
        /// <param name="exception">The exception to log.</param>
        /// <param name="format">The message or format template.</param>
        /// <param name="args">Any arguments required for the format template.</param>
        public override void Fatal(Exception exception, string format, params object[] args)
        {
            LogInternal(LogLevel.Fatal, format, args, exception);
        }

        #endregion

        #region Method

        private void LogInternal(LogLevel level, string message)
        {
            var logEvent = new LogEventInfo(level, _logger.Name, message);
            _logger.Log(typeof (NLogLogger), logEvent);
        }

        private void LogInternal(LogLevel level, string message, Exception exception)
        {
            var logEvent = new LogEventInfo(level, _logger.Name, null, "{0}", new object[] {message}, exception);
            _logger.Log(typeof(NLogLogger), logEvent);
        }

        private void LogInternal(LogLevel level, string format, object[] args)
        {
            var logEvent = new LogEventInfo(level, _logger.Name, null, format, args);
            _logger.Log(typeof (NLogLogger), logEvent);
        }

        private void LogInternal(LogLevel level, string format, object[] args, Exception exception)
        {
            var logEvent = new LogEventInfo(level, _logger.Name, null, format, args, exception);
            _logger.Log(typeof (NLogLogger), logEvent);
        }

        #endregion
    }
}